home *** CD-ROM | disk | FTP | other *** search
/ Personal Computer World 2009 February / PCWFEB09.iso / Software / Linux / Kubuntu 8.10 / kubuntu-8.10-desktop-i386.iso / casper / filesystem.squashfs / usr / share / pyshared / GDebi / GDebiKDE.py < prev    next >
Text File  |  2008-08-05  |  18KB  |  420 lines

  1. #!/usr/bin/python
  2. # -*- coding: utf-8 -*-
  3. #
  4. # Copyright (c) 2005-2007 Martin B├╢hm
  5. # Copyright (c) 2008 Canonical Ltd
  6. #
  7. # AUTHOR:
  8. # Martin B├╢hm <martin.bohm@ubuntu.com>
  9. #
  10. # This file is part of GDebi
  11. #
  12. # GDebi is free software; you can redistribute it and/or
  13. # modify it under the terms of the GNU General Public License as published
  14. # by the Free Software Foundation; either version 2 of the License, or (at
  15. # your option) any later version.
  16. #
  17. # GDebi is distributed in the hope that it will be useful,
  18. # but WITHOUT ANY WARRANTY; without even the implied warranty of
  19. # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  20. # General Public License for more details.
  21. #
  22. # You should have received a copy of the GNU General Public License
  23. # along with this program.  If not, see <http://www.gnu.org/licenses/>.
  24.  
  25. import os
  26. import subprocess
  27. import string
  28. import re
  29. import pty
  30. import warnings
  31. warnings.filterwarnings("ignore", "apt API not stable yet", FutureWarning)
  32. import apt_pkg
  33.  
  34. from PyKDE4.kdecore import *
  35. from PyKDE4.kdeui import *
  36. from PyQt4.QtCore import *
  37. from PyQt4.QtGui import *
  38. from PyQt4 import uic
  39.  
  40. from DebPackage import DebPackage, Cache
  41. import gettext
  42. from GDebiCommon import GDebiCommon
  43. from KDEAptDialogs import *
  44.  
  45. def _(str):
  46.     return unicode(gettext.gettext(str), 'UTF-8')
  47. def __(catalog,str):
  48.     return unicode(gettext.dgettext(catalog, str), 'UTF-8')
  49. def utf8(str):
  50.   if isinstance(str, unicode):
  51.       return str
  52.   return unicode(str, 'UTF-8')
  53.  
  54. def loadUi(file, parent):
  55.     """load local file if possible else use installed file"""
  56.     if os.path.exists("data/" + file):
  57.         uic.loadUi("data/" + file, parent)
  58.     else:
  59.         uic.loadUi("/usr/share/gdebi/" + file, parent)
  60.  
  61. class DumbTerminal(QTextEdit):
  62.     """ a very dumb terminal """
  63.     def __init__(self, parent_frame):
  64.         """ really dumb terminal with simple editing support """
  65.         QTextEdit.__init__(self, parent_frame)
  66.         self.setFontFamily("Monospace")
  67.         self.setFontPointSize(8)
  68.         self.setWordWrapMode(QTextOption.NoWrap)
  69.         self.setUndoRedoEnabled(False)
  70.         self._block = False
  71.         self.connect(self, SIGNAL("cursorPositionChanged(int,int)"), self.onCursorPositionChanged)
  72.  
  73.     def setInstallProgress(self, installProgress):
  74.         self.installProgress = installProgress
  75.  
  76.     def insertWithTermCodes(self, text):
  77.         """ support basic terminal codes """
  78.         display_text = ""
  79.         for c in text:
  80.             # \b - backspace
  81.             if c == chr(8):
  82.                 self.moveCursor(QTextEdit.MoveBackward, QTextCursor.KeepAnchor)
  83.                 self.cut() #self.removeSelectedText()  FIXME
  84.             # \r - is filtered out
  85.             elif c == chr(13):
  86.                 pass
  87.             # \a - bell - ignore for now
  88.             elif c == chr(7):
  89.                 pass
  90.             else:
  91.                 display_text += c
  92.         self.insertPlainText(display_text)
  93.  
  94.     def keyPressEvent(self, ev):
  95.         """ send (ascii) key events to the pty """
  96.         # no master_fd yet
  97.         if not hasattr(self.installProgress, "master_fd"):
  98.             return
  99.         # special handling for backspace
  100.         if ev.key() == Qt.Key_Backspace:
  101.             #print "sent backspace"
  102.             os.write(self.installProgress.master_fd, chr(8))
  103.             return
  104.         # do nothing for events like "shift" 
  105.         if not ev.text():
  106.             return
  107.         # now sent the key event to the termianl as utf-8
  108.         os.write(self.installProgress.master_fd, ev.text().toUtf8())
  109.  
  110.     def onCursorPositionChanged(self, x, y):
  111.         """ helper that ensures that the cursor is always at the end """
  112.         if self._block:
  113.             return
  114.         # block signals so that we do not run into a recursion
  115.         self._block = True
  116.         para = self.paragraphs() - 1
  117.         pos = self.paragraphLength(para)
  118.         self.moveCursor(QTextCursor.End)
  119.         self._block = False
  120.  
  121. class GDebiKDEDialog(QDialog):
  122.     """Our main user interface, load from UI file"""
  123.     def __init__(self, parent):
  124.         QDialog.__init__(self, parent)
  125.         loadUi("GDebiKDEDialog.ui", self)
  126.  
  127. class GDebiKDE(GDebiCommon, GDebiKDEDialog):
  128.     def __init__(self,datadir,options,file="",parent = None,name = None,modal = 0,fl = 0):
  129.         GDebiKDEDialog.__init__(self,parent)
  130.         GDebiCommon.__init__(self,datadir,options,file)
  131.         # load the icon
  132.         self.setWindowIcon(KIcon("adept_installer"))
  133.         # first, we load all the default descriptions -- pyuic doesn't use
  134.         # gettext as default (FIXME, copy code from language-selector)
  135.         self.textLabel1.setText(_("Package:"))
  136.         self.textLabel1_2.setText(_("Status:"))
  137.         self.detailsButton.setText(_("Details"))
  138.         self.tabWidget2.setTabText(0,_("Description"))
  139.         self.tabWidget2.setTabText(1,_("Details"))
  140.         self.tabWidget2.setTabText(2,_("Included Files"))
  141.         self.cancelButton.setText(__("kdelibs","&Cancel"))
  142.         self.installButton.setText(_("&Install Package"))
  143.         self.DetailsVersionLabel.setText(_("<b>Version:</b>"))
  144.         self.DetailsMaintainerLabel.setText(_("<b>Maintainer:</b>"))
  145.         self.DetailsPriorityLabel.setText(_("<b>Priority:</b>"))
  146.         self.DetailsSectionLabel.setText(_("<b>Section:</b>"))
  147.         self.DetailsSizeLabel.setText(_("<b>Size:</b>"))
  148.         # translation finished
  149.         self.setDisabled(True)
  150.         self.PackageProgressBar.setEnabled(True)
  151.         self.detailsButton.hide()
  152.         self.installButton.setIcon(KIcon("dialog-ok"))
  153.         self.cancelButton.setIcon(KIcon("dialog-cancel"))
  154.         self.show()
  155.         self.kapp = KApplication.kApplication() #incidently, this stops it crashing on quit, no idea why, jriddell
  156.         self.kapp.processEvents() #run because openCache takes a while to do its thing
  157.         self.cprogress = CacheProgressAdapter(self.PackageProgressBar)
  158.         if not self.openCache():
  159.             KMessageBox.error(self, '<b>' + self.error_header + '</b><br>' + self.error_body,
  160.                 self.error_header)
  161.             sys.exit(1)
  162.         # try to open the file
  163.         if file != "" and os.path.exists(file):
  164.             self.open(file)
  165.         else:
  166.             header = _("The package file does not exist")
  167.             body = _("A nonexistent file has been selected for installation. Please select an existing .deb package file.")
  168.             KMessageBox.error(self, '<b>' + header + '</b><br>' + body, header)
  169.             sys.exit(1)
  170.  
  171.         self.setEnabled(True)
  172.         self.PackageProgressBar.hide()
  173.         self.connect(self.cancelButton, SIGNAL("clicked()"), self.cancelButtonClicked)
  174.         self.connect(self.installButton, SIGNAL("clicked()"), self.installButtonClicked)
  175.         self.connect(self.detailsButton, SIGNAL("clicked()"), self.detailsButtonClicked)
  176.  
  177.     def open(self, file):
  178.         """ load the .deb file """
  179.         res = GDebiCommon.open(self, file)
  180.         if res == False:
  181.             KMessageBox.error(self, '<b>' + self.error_header + '</b><br>' + self.error_body, self.error_header)
  182.             return False
  183.  
  184.         # set name
  185.         self.setWindowTitle(_("Package Installer - %s") % self._deb.pkgName)
  186.         self.textLabel1_3.setText(self._deb.pkgName)
  187.  
  188.         # set description
  189.         buf = self.DecriptionEdit
  190.         try:
  191.             long_desc = ""
  192.             raw_desc = string.split(utf8(self._deb["Description"]), "\n")
  193.             # append a newline to the summary in the first line
  194.             summary = raw_desc[0]
  195.             raw_desc[0] = ""
  196.             long_desc = "%s\n" % summary
  197.             for line in raw_desc:
  198.                 tmp = string.strip(line)
  199.                 if tmp == ".":
  200.                     long_desc += "\n"
  201.                 else:
  202.                     long_desc += tmp + "\n"
  203.             # do some regular expression magic on the description
  204.             # Add a newline before each bullet
  205.             p = re.compile(r'^(\s|\t)*(\*|0|-)',re.MULTILINE)
  206.             long_desc = p.sub('\n*', long_desc)
  207.             # add the <b> tag to the first line
  208.             long_desc = re.sub(r'\n','</b>\n',long_desc,1)
  209.             # replace all newlines by spaces
  210.             p = re.compile(r'\n', re.MULTILINE)
  211.             long_desc = p.sub(" ", long_desc)
  212.             # replace all multiple spaces by
  213.             # paragraph tags
  214.             p = re.compile(r'\s\s+', re.MULTILINE)
  215.             long_desc = p.sub("</p><p>", long_desc)
  216.             # add the remaining tags
  217.             long_desc = '<p><b>' + long_desc + '</p>'
  218.             # write the descr string to the buffer
  219.             buf.setText(long_desc)
  220.         except KeyError:
  221.             buf.setText(_("No description is available"))
  222.  
  223.         # check deps
  224.         if not self._deb.checkDeb():
  225.             self.installButton.setEnabled(False)
  226.             self.textLabel1_3_2.setText("<font color=\"#ff0000\"> Error: " + self._deb._failureString + "</font>")
  227.             self.detailsButton.hide()
  228.             return False
  229.  
  230.         # set version_info_{msg,title} strings
  231.         self.compareDebWithCache()
  232.  
  233.         if self._deb.compareToVersionInCache() == DebPackage.VERSION_SAME:
  234.             #self.textLabel1_3_2.setText(_("Same version is already installed"))
  235.             self.installButton.setText(_("&Reinstall Package"))
  236.             self.installButton.setIcon(KIcon("view-refresh"))
  237.             #TODO
  238.             #self.button_install.grab_default()
  239.             #self.button_install.set_sensitive(True)
  240.             #self.button_details.hide()
  241.  
  242.         # load changes into (self.install, self.remove, self.unauthenticated)
  243.         self.getChanges()
  244.  
  245.         if self.version_info_title != "" and self.version_info_msg != "":
  246.             self.infoIcon.setPixmap(DesktopIcon("dialog-information"))
  247.             self.infoBox.setText(self.version_info_title + '\n' + self.version_info_msg)
  248.  
  249.         if len(self.remove) == len(self.install) == 0:
  250.             pass # handled by common core
  251.         else:
  252.             self.detailsButton.show()
  253.  
  254.         self.textLabel1_3_2.setText(self.deps)
  255.         # set various status bits
  256.         self.DetailsVersion.setText(self._deb["Version"])
  257.         self.DetailsMaintainer.setText(utf8(self._deb["Maintainer"]))
  258.         self.DetailsPriority.setText(self._deb["Priority"])
  259.         self.DetailsSection.setText(utf8(self._deb["Section"]))
  260.         self.DetailsSize.setText(self._deb["Installed-Size"] + " KB")
  261.  
  262.         # set filelist
  263.         buf = self.IncFilesEdit
  264.         buf.setText("\n".join(self._deb.filelist))
  265.  
  266.         if not self._deb.checkDeb():
  267.             self.installButton.setText(_("&Install Package"))
  268.  
  269.         if self._deb.compareToVersionInCache() == DebPackage.VERSION_SAME:
  270.             self.installButton.setText(_("Re&install Package"))
  271.  
  272.     def cancelButtonClicked(self):
  273.         self.close()
  274.  
  275.     def detailsButtonClicked(self):
  276.         changedList = QStringList()
  277.         (install, remove, unauthenticated) = self._deb.requiredChanges
  278.         for i in install:
  279.             changedList.append(_("To be installed: %s") % i)
  280.         for r in remove:
  281.             changedList.append(_("To be removed: %s") % r)
  282.  
  283.         infoReport = KMessageBox.informationList(self,
  284.                       _("<b>To install the following changes are required:</b>"),
  285.                       changedList, _("Details"))
  286.  
  287.     def installButtonClicked(self):
  288.         # if not root, start a new instance
  289.         if os.getuid() != 0:
  290.             if os.path.exists("gdebi-kde"):
  291.                 executable = os.path.curdir + "/gdebi-kde"
  292.             else:
  293.                 executable = "/usr/bin/gdebi-kde"
  294.             print "executable " + executable
  295.             os.execl("/usr/bin/kdesudo", "kdesudo", executable + " -n ", self._deb.file)
  296.             self.kapp.exit()
  297.  
  298.         if not self.try_acquire_lock():
  299.             KMessageBox.error(self, '<b>' + self.error_header + '</b><br>' + self.error_body, self.error_header)
  300.             return False
  301.         if not self.try_acquire_lock():
  302.             KMessageBox.error(self, '<b>' + self.error_header + '</b><br>' + self.error_body, self.error_header)
  303.             return False
  304.         # set the window as disabled
  305.         self.setDisabled(True)
  306.         self.installDialog = GDebiKDEInstall(self)
  307.         self.installDialog.show()
  308.  
  309.         # FIXME: use the new python-apt acquire interface here,
  310.         # or rather use it in the apt module and raise exception
  311.         # when stuff goes wrong!
  312.         if len(self.install) > 0 or len(self.remove) > 0:
  313.             #if not self.acquire_lock():
  314.             if not self.acquire_lock():
  315.                 #self.show_alert(gtk.MESSAGE_ERROR, self.error_header, self.error_body)
  316.                 KMessageBox.sorry(self, '<b>' + self.error_header + '</b><br>' + self.error_body, self.error_header)
  317.                 return False
  318.             fprogress = KDEFetchProgressAdapter(self.installDialog.installationProgress,
  319.                                                 self.installDialog.installingLabel,
  320.                                                 self.installDialog)
  321.             iprogress = KDEInstallProgressAdapter(self.installDialog.installationProgress,
  322.                                                   self.installDialog.installingLabel,
  323.                                                   self.installDialog)
  324.             self.installDialog.konsole.setInstallProgress(iprogress)
  325.             errMsg = None
  326.             try:
  327.                 res = self._cache.commit(fprogress,iprogress)
  328.             except IOError, msg:
  329.                 res = False
  330.                 errMsg = "%s" % msg
  331.                 header = _("Could not download all required files")
  332.                 body = _("Please check your internet connection or "
  333.                             "installation medium.")
  334.             except SystemError, msg:
  335.                 res = False
  336.                 header = _("Could not install all dependencies")
  337.                 body = _("Usually this is related to an error of the "
  338.                         "software distributor. See the terminal window for "
  339.                         "more details.")
  340.             if not res:
  341.                 #print "something bad happend"
  342.                 self.errorReport = KMessageBox.error(self, header + "<br>" + body, header)
  343.                 return
  344.  
  345.         # install the package itself
  346.         #self.label_action.set_markup("<b><big>"+_("Installing package file")+"</big></b>")
  347.         dprogress = KDEDpkgInstallProgress(self._deb.file,
  348.                                              self.installDialog.installingLabel,
  349.                                              self.installDialog.installationProgress,
  350.                                              self.installDialog.konsole, self.installDialog)
  351.         dprogress.commit()
  352.         #self.label_action.set_markup("<b><big>"+_("Package installed")+"</big></b>")
  353.         # show the button
  354.         #self.button_deb_install_close.set_sensitive(True)
  355.         #self.button_deb_install_close.grab_default()
  356.         self.installDialog.setWindowTitle(_("Installation finished"))
  357.         if dprogress.exitstatus == 0:
  358.             self.installDialog.installingLabel.setText(_("<b>" + "Package '%s' was installed" + "</b>") % self._deb.pkgName)
  359.         else:
  360.             self.installDialog.installingLabel.setText("<b>"+_("Failed to install package '%s'") % os.path.basename(self._deb.file)+"</b>")
  361.             self.installDialog.konsoleFrame.show()
  362.         #self.statusbar_main.push(self.context,_("Installation complete"))
  363.         # FIXME: Doesn't stop notifying
  364.         #self.window_main.set_property("urgency-hint", 1)
  365.  
  366.         # reopen the cache, reread the file, FIXME: add progress reporting
  367.         #self._cache = Cache(self.cprogress)
  368.         self._cache = Cache()
  369.         if self._cache._depcache.BrokenCount > 0:
  370.             header = _("Failed to completely install all dependencies")
  371.             text = _("To fix this run 'sudo apt-get install -f' in a "
  372.                          "terminal window.")
  373.             self.errorReport = KMessageBox.error(self, header + text, header)
  374.             sys.exit(1)
  375.  
  376. class GDebiKDEInstall(QDialog):
  377.     def __init__(self, parent):
  378.         QDialog.__init__(self, parent)
  379.         loadUi("GDebiKDEInstallDialog.ui", self)
  380.         self.showDetailsButton.setText(__("libept","Show Details")) #FIXME check i18n
  381.         self.closeButton.setText(__("kdelibs","&Close"))
  382.         self.showDetailsButton.setIcon(KIcon("utilities-terminal"))
  383.         self.closeButton.setIcon(KIcon("window-close"))
  384.         self.closeButton.setEnabled(False)
  385.         self.closeButton.setVisible(False)
  386.         self.parent = parent
  387.         self.konsole = None
  388.         self.konsoleFrameLayout = QHBoxLayout(self.konsoleFrame)
  389.         self.konsoleFrame.hide()
  390.         self.newKonsole()
  391.         kapp = KApplication.kApplication()
  392.         kapp.processEvents()
  393.  
  394.     def newKonsole(self):
  395.         self.konsole = DumbTerminal(self.konsoleFrame)
  396.         self.konsoleFrame.setMinimumSize(500, 400)
  397.         self.konsoleFrameLayout.addWidget(self.konsole)
  398.  
  399.     def showTerminal(self):
  400.         if self.konsoleFrame.isVisible():
  401.             self.konsoleFrame.hide()
  402.             self.showDetailsButton.setText(__("libept","Show Details"))
  403.             QTimer.singleShot(1, self.changeSize)
  404.         else:
  405.             self.konsoleFrame.show()
  406.             self.showDetailsButton.setText(__("libept","Hide Details"))
  407.  
  408.     def changeSize(self):
  409.         self.resize(self.minimumSize())
  410.  
  411.     def closeButtonClicked(self):
  412.         self.close()
  413.  
  414.     def closeEvent(self, event):
  415.         self.close()
  416.  
  417.     def close(self):
  418.         self.accept()
  419.         KApplication.kApplication().exit()
  420.